/*
 * Copyright (c) 2011, Julien Lamy
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the project's author nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "track.h"

#include <istream>
#include <map>

#include <QRegExp>
#include <QString>
#include <QStringList>

#include "chunkreader.h"
#include "dataobject.h"

std::map<QString, DataObjectType::Type> Track::field_name_to_data_object_type_;
bool const Track::initialized(Track::initialize_static_data());

QString Track::filename(QString const & format,
                        bool remove_illegal_characters,
                        QString const & illegal_characters_replacement) const
{
    QString result(format);

    QStringList const text_fields = QString(
        "album|artist|composer|genre|title").split("|");
    for(QStringList::const_iterator it=text_fields.begin(); it!=text_fields.end(); ++it)
    {
        std::map<QString, DataObjectType::Type>::const_iterator const data_object_type_it =
            Track::field_name_to_data_object_type_.find(*it);

        QString replacement((*this)[data_object_type_it->second]);
        if(remove_illegal_characters)
        {
            static QRegExp const illegal_characters("[/\\:*?\"<>|]");
            replacement.replace(illegal_characters, illegal_characters_replacement);
        }

        result.replace("<"+*it+">", replacement);
    }
    
    QStringList const number_fields = QString(
        "disk_number|total_disks|track_number|total_tracks|year").split("|");
    for(QStringList::const_iterator it=number_fields.begin(); it!=number_fields.end(); ++it)
    {
        QRegExp const pattern("<"+*it+"(?:,(\\d+))?>");

        int begin=0;
        while((begin = pattern.indexIn(result, begin)) != -1)
        {
            unsigned int const precision = pattern.cap(1).toUInt();

            QString replacement;
            if(*it == "disk_number")
            {
                replacement = QString::number(this->disk_number);
            }
            else if(*it == "total_disks")
            {
                replacement = QString::number(this->total_disks);
            }
            else if(*it == "track_number")
            {
                replacement = QString::number(this->track_number);
            }
            else if(*it == "total_tracks")
            {
                replacement = QString::number(this->total_tracks);
            }
            else if(*it == "year")
            {
                replacement = QString::number(this->year);
            }
            replacement = replacement.rightJustified(precision, '0');
            result.replace(pattern, replacement);
            begin += replacement.length();
        }
    }

    QString const & location = (*this)[DataObjectType::LOCATION];
    QString const suffix = location.split(".").last();
    result += "." + suffix;

    return result;
}

bool Track::initialize_static_data()
{
    Track::field_name_to_data_object_type_["album"] = DataObjectType::ALBUM;
    Track::field_name_to_data_object_type_["artist"] = DataObjectType::ARTIST;
    Track::field_name_to_data_object_type_["composer"] = DataObjectType::COMPOSER;
    Track::field_name_to_data_object_type_["genre"] = DataObjectType::GENRE;
    Track::field_name_to_data_object_type_["title"] = DataObjectType::TITLE;
    
    return true;
}

std::istream& operator>>(std::istream & stream, Track & track)
{
    ChunkReader reader(stream, "mhit");

    uint32_t number_of_strings;
    reader.read(number_of_strings);

    if(!reader.done()) reader.read(track.unique_id);
    if(!reader.done()) reader.read(track.visible);
    if(!reader.done()) reader.read(track.file_type);
    if(!reader.done()) reader.read(track.type_1);
    if(!reader.done()) reader.read(track.type_2);
    if(!reader.done()) reader.read(track.compilation);
    if(!reader.done()) reader.read(track.rating);
    if(!reader.done()) reader.read(track.last_modified_time);
    if(!reader.done()) reader.read(track.size);
    if(!reader.done()) reader.read(track.length);
    if(!reader.done()) reader.read(track.track_number);
    if(!reader.done()) reader.read(track.total_tracks);
    if(!reader.done()) reader.read(track.year);
    if(!reader.done()) reader.read(track.bit_rate);
    if(!reader.done()) reader.read(track.sample_rate);
    if(!reader.done()) reader.read(track.volume);
    if(!reader.done()) reader.read(track.start_time);
    if(!reader.done()) reader.read(track.stop_time);
    if(!reader.done()) reader.read(track.sound_check);
    if(!reader.done()) reader.read(track.play_count);
    if(!reader.done()) reader.read(track.play_count_2);
    if(!reader.done()) reader.read(track.last_played_time);
    if(!reader.done()) reader.read(track.disk_number);
    if(!reader.done()) reader.read(track.total_disks);
    if(!reader.done()) reader.read(track.user_id);
    if(!reader.done()) reader.read(track.date_added);
    if(!reader.done()) reader.read(track.bookmark_time);
    if(!reader.done()) reader.read(track.db_id);
    if(!reader.done()) reader.read(track.checked);
    if(!reader.done()) reader.read(track.application_rating);
    if(!reader.done()) reader.read(track.bpm);
    if(!reader.done()) reader.read(track.artwork_count);
    if(!reader.done()) reader.read(track.unknown_1);
    if(!reader.done()) reader.read(track.artwork_size);
    if(!reader.done()) reader.read(track.unknown_2);
    if(!reader.done()) reader.read(track.sample_rate_2);
    if(!reader.done()) reader.read(track.date_released);
    if(!reader.done()) reader.read(track.unknown_3);
    if(!reader.done()) reader.read(track.explicit_flag);
    if(!reader.done()) reader.read(track.unknown_4);
    if(!reader.done()) reader.read(track.unknown_5);
    if(!reader.done()) reader.read(track.skip_count);
    if(!reader.done()) reader.read(track.last_skipped);
    if(!reader.done()) reader.read(track.has_artwork);
    if(!reader.done()) reader.read(track.skip_when_shuffling);
    if(!reader.done()) reader.read(track.remember_playback_position);
    if(!reader.done()) reader.read(track.flag_4);
    if(!reader.done()) reader.read(track.db_id_2);
    if(!reader.done()) reader.read(track.lyrics_flags);
    if(!reader.done()) reader.read(track.movie_file_flags);
    if(!reader.done()) reader.read(track.played_mark);
    if(!reader.done()) reader.read(track.unknown_6);
    if(!reader.done()) reader.read(track.unknown_7);
    if(!reader.done()) reader.read(track.pre_gap);
    if(!reader.done()) reader.read(track.sample_count);
    if(!reader.done()) reader.read(track.unknown_8);
    if(!reader.done()) reader.read(track.post_gap);
    if(!reader.done()) reader.read(track.unknown_9);
    if(!reader.done()) reader.read(track.media_type);
    if(!reader.done()) reader.read(track.season_number);
    if(!reader.done()) reader.read(track.episode_number);
    if(!reader.done()) reader.read(track.unknown_10);
    if(!reader.done()) reader.read(track.unknown_11);
    if(!reader.done()) reader.read(track.unknown_12);
    if(!reader.done()) reader.read(track.unknown_13);
    if(!reader.done()) reader.read(track.unknown_14);
    if(!reader.done()) reader.read(track.unknown_15);
    if(!reader.done()) reader.read(track.unknown_16);
    if(!reader.done()) reader.read(track.gapless_data);
    if(!reader.done()) reader.read(track.unknown_17);
    if(!reader.done()) reader.read(track.gapless_track_flag);
    if(!reader.done()) reader.read(track.gapless_album_flag);
    if(!reader.done()) reader.read(track.unknown_18, 20);
    if(!reader.done()) reader.read(track.unknown_19);
    if(!reader.done()) reader.read(track.unknown_20);
    if(!reader.done()) reader.read(track.unknown_21);
    if(!reader.done()) reader.read(track.unknown_22);
    if(!reader.done()) reader.read(track.unknown_23);
    if(!reader.done()) reader.read(track.album_id);

    reader.ignore_rest_of_header();

    track.parse(stream, number_of_strings);

    return stream;
}
